<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>
        Inheritance No.2 Create Inheritance && Combination Inheritance
    </title>
</head>
<body>
    构造函数式继承
    组合继承
</body>
<script>
    // 2 构造函数式继承 再次顾名思义，通过构造函数的处理来完成继承

    //我们不用修改，直接从类式继承把Father搬过来，不过把age变成一个可传参的变量
    function Father(age){
        this.name = '爸爸';
        this.age = age;   //爸爸28岁
        this.sex = '男';
        this.body = ['172','70'];
        this.hand = {
            'wristPower' : 123,
            'handPower' : 123
        }
    }

    //我们把drink类去掉，因为他偏离了我的设想。没啥用。。。

    // 保留eat属性，用它作为测试方法
    Father.prototype.eat=function(){
        console.log(this.name+"吃饭");
        return this.sex+this.name;
    }

    //注意啦，构造函数式继承的核心来了
    function Son(age){
        Father.call(this,age); //核心语句，先来看看call是啥意思

        //call方法: 
        // 语法：call([thisObj[,arg1[, arg2[,   [,.argN]]]]]) 
        // 定义：调用一个对象的一个方法，以另一个对象替换当前对象。 
        // 说明： 
        // call 方法可以用来代替另一个对象调用一个方法。call 方法可将一个函数的对象上下文从初始的上下文改变为由 thisObj 指定的新对象。 
        // 如果没有提供 thisObj 参数，那么 Global 对象被用作 thisObj。 

        //是不是很难理解，再来个实例代码

        /*****************下面这段是call的示例代码************************/
        // function add(a,b)  
        // {  
        //     alert(a+b);  
        // }  
        // function sub(a,b)  
        // {  
        //     alert(a-b);  
        // }  
        
        // add.call(sub,3,1);  

        //这个例子中的意思就是用 add 来替换 sub，add.call(sub,3,1) == add(3,1) ，所以运行结果为：alert(4); 
        // 注意：js 中的函数其实是对象，函数名是对 Function 对象的引用。

        //还蒙？那尝试用我的方式理解
        //看到call之后，你就把他第一个参数变成一个变量
        //  这里this指的是Son
        //  然后把调用call的对象作为函数名，第二个参数开始之后的参数作为函数参数
        //  改过来就成了
        //  于是就成了Son = Father(age);
        //  结局就是Son把Father里的所有属性都拷贝下来了
           
    }

    /*****************下面这句话，看到文档最后再解封哦**********************************/
    //Son.prototype = new Father();     //我是类式继承的核心语句，暂时被封印了，当被解封，请叫这个例子为组合模式继承

    /*****************这句话比上面更牛**********************************/
    //Son.prototype = Object.create(Father.prototype); //这句话是上句话的装逼写法，大概意思就是拷贝了一个Father的prototype产生对象，同时避免了Father重复构造。

    /******************玩到这你有没有曾经想过这样*******************************************/
    //Son.prototype = Father.prototype   //是什么结果。。。我希望你试了告诉我，有啥问题，也到你们思考的时候了

    var XiaoMing = new Son(2) //小明今年2岁
    var XiaoHong = new Son(3) //姐姐小红今年3岁

    console.log(XiaoMing.age); //2
    console.log(XiaoHong.age); //3

    //没毛病。我们并没有给子类Son中加age属性，但是成功给父类中的age赋值了。解决了类式继承的问题
    //那我们在类式继承中纠结的坑这里会不会有呢？

    console.log("-------赋值修改法----------")
    XiaoHong.sex = '女' //人家是女孩子
    console.log(XiaoHong.sex); //女
    console.log(XiaoMing.sex); //男

    //强行加入一个数组，通过另一个实例push入数组
    console.log("-------数组对象操作修改法----------")
    console.log(XiaoMing.body); //[172,70]
    XiaoHong.body.push('C');
    console.log(XiaoHong.body);  //[172,70,C]
    console.log(XiaoMing.body);  //[172,70]

    //绝对不会，因为小明是小明，小红是小红。在构造函数中的属性，实例化时是会自动copy出来的
    //当然，这么做也有问题，我想用父类原型中的eat
    XiaoHong.eat(); // XiaoHong.eat is not a function

    //明显发现，这个问题，刚刚类式继承可以解决嘛。把这两组合起来，不就可以了？
    //太机智了小伙伴们，类式继承+构造函数式继承，叫组合继承，是js中比较完美的一种继承方式。

//     还能更完美？当然，程序员就是应该对每一处性能精益求精，有没有发现，我们在创建Son实例的时候，会执行一次Father的构造函数吧
//     那在Son.prototype = new Father()的时候还会执行一次Father的构造函数，太多余了吧。
//     于是我们采用Object.create()函数搞事情

//     Object.create() 是什么？

// 　　Object.create(proto [, propertiesObject ]) 是E5中提出的一种新的对象创建方式，第一个参数是要继承的原型，如果不是一个子函数，可以传一个null，第二个参数是对象的属性描述符，这个参数是可选的。

// 这样也就完美了。当然这玩意儿是ES5后期才出来的。在这之前有个大师用存原生js也实现了这个功能，下个demo我们再来玩一玩它

</script>
</html>
  
